package com.spider.im.login.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.spider.im.common.annotation.RedisLock;
import com.spider.im.common.aspect.BusinessException;
import com.spider.im.common.constant.RedisKey;
import com.spider.im.common.constant.RespCodeEnum;
import com.spider.im.common.security.JwtUtil;
import com.spider.im.common.utils.EncryptionUtils;
import com.spider.im.login.annotation.LoginType;
import com.spider.im.login.enums.LoginTypeEnum;
import com.spider.im.login.req.LoginReq;
import com.spider.im.login.req.RegisterReq;
import com.spider.im.login.resp.LoginUser;
import com.spider.im.sms.service.SmsService;
import com.spider.im.user.entity.User;
import com.spider.im.user.req.UserReq;
import com.spider.im.user.resp.UserResp;
import com.spider.im.user.service.UserService;
import io.netty.util.internal.ThrowableUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * 短信登陆
 *
 */
@LoginType(type = LoginTypeEnum.PHONE)
@Service
@Slf4j
public class SmsLoginServiceImpl implements LoginService {


    @Resource
    private UserService userService;

    @Resource
    private SmsService smsService;

    @Resource
    private JwtUtil jwtTokenUtil;

    @Resource
    private RedissonClient redissonClient;


    @Override
    public LoginUser login(LoginReq req) {

        String verificationCode = req.getVerificationCode();
        String encryptPhone = req.getPhone();
        if (StrUtil.isBlank(encryptPhone)) {
            log.error("手机号码不能为空 : {}", encryptPhone);
            throw new BusinessException(RespCodeEnum.PHONE_NOT_NULL);
        }
        String key = DigestUtil.md5Hex(encryptPhone);
        RLock lock = redissonClient.getLock(RedisKey.REDIS_LOCK_KEY + key);
        try {
            boolean tryLock = lock.tryLock(0, 60, TimeUnit.SECONDS);
            if (!tryLock) {
                log.warn("业务繁忙 : {}", RedisKey.REDIS_LOCK_KEY + key);
                throw new BusinessException(RespCodeEnum.REDIS_LOCK);
            }
        } catch (InterruptedException e) {
            log.error("获取锁异常 : {}", ThrowableUtil.stackTraceToString(e));
            throw new BusinessException(RespCodeEnum.REDIS_ERROR_LOCK, e);
        }
        boolean verified = smsService.verifyCode(encryptPhone, verificationCode);
        if (!verified) {
            log.error("验证码错误 : {}", verificationCode);
            throw new BusinessException(RespCodeEnum.VERIFICATION_CODE_EXPIRED);
        }

        List<User> userList = userService.list(new LambdaQueryWrapper<User>().eq(User::getPhone, encryptPhone));
        UserResp userResp = null;
        if (CollectionUtil.isEmpty(userList)) {
           //  注册用户
            UserReq userReq = new UserReq();
            BeanUtil.copyProperties(req, userReq);
            userResp =  userService.registerPhone(userReq);
        } else {
           User user = userList.get(0);
             userResp = new UserResp();
            BeanUtil.copyProperties(user, userResp);
        }
        req.setPhone(encryptPhone);
        // 生成token
        final String token = jwtTokenUtil.generateToken(userResp);
        LoginUser loginUser = new LoginUser();
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setToken(token);
        loginUser.setUserResp(userResp);
        loginUser.setUserId(userResp.getId());
        return loginUser;
    }
}
